package com.hsogoo.ultraman.service;

import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.google.common.collect.Maps;
import com.hsogoo.ultraman.Constant;
import com.hsogoo.ultraman.NamespaceConfig;
import com.hsogoo.ultraman.dao.ConfigDao;
import com.hsogoo.ultraman.dao.NamespaceDao;
import com.hsogoo.ultraman.dto.ConfigDto;
import com.hsogoo.ultraman.dto.NamespaceDto;
import com.hsogoo.ultraman.monitor.ZkClient;
import com.hsogoo.ultraman.util.AppendUtil;
import com.hsogoo.ultraman.util.ExceptionUtil;
import com.hsogoo.ultraman.util.NetworkUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by za-huangsaigang on 2018/9/19.
 */
@Service
@Slf4j
public class DefaultConfigServer implements ConfigServer, InitializingBean {

    private ZkClient zkClient;
    @Value("${server.port}")
    private String serverPort;
    @Value("${registry.url}")
    private String registryUrl;
    @Autowired
    private NamespaceDao namespaceDao;
    @Autowired
    private ConfigDao configDao;
    private AtomicLong publishId = new AtomicLong(0);

    @Override
    public void register() {
        String localIp = NetworkUtil.getLocalIpString();
        String path = AppendUtil.appendString(Constant.CONFIG_SERVER_LIST, Constant.PATH_PREFIX, localIp, Constant.IP_PORT_SEPARATOR, serverPort);
        if (zkClient != null) {
            try{
                zkClient.createNode(path, CreateMode.EPHEMERAL);
                log.info("configServer registered [{}:{}]", localIp, serverPort);
            }catch (Exception ex){
                log.error("configServer register exception:[{}]", ExceptionUtil.getDetailMessage(ex));
            }
        }
    }

    @Override
    public void notifyPublish(String env, String app, String namespace) {
        log.info("write zk node {}/{}/{}/{}", Constant.CONFIG_PUBLISH_NODE, env, app, namespace);
        String publishPath = AppendUtil.appendString(Constant.CONFIG_PUBLISH_NODE,Constant.PATH_PREFIX, env,
                Constant.PATH_PREFIX, app, Constant.PATH_PREFIX, namespace);
        try {
            zkClient.write(publishPath, String.valueOf(publishId.incrementAndGet()));
        }catch (Exception e){
            log.error("publish config exception" + ExceptionUtil.getDetailMessage(e));
        }
    }


    @Override
    public List<String> findAllConfigServer() {
        return zkClient.getAllServer();
    }

    @Override
    public NamespaceConfig findNamespaceConfig(String env, String app, String namespace) {
        NamespaceConfig result = new NamespaceConfig();
        result.setAppName(app);
        result.setEnvName(env);
        result.setNamespaceName(namespace);
        result.setConfigurations(Maps.newHashMap());
        NamespaceDto queryNamespace = assembleNamespace(env, app, namespace);
        NamespaceDto namespaceDto = namespaceDao.findNamespace(queryNamespace);
        //TODO:MOCK
        List<ConfigDto> configDtoList = configDao.findConfigDtoByNamespace(namespaceDto.getId());
        for(ConfigDto config : configDtoList){
            result.getConfigurations().put(config.getKey(), config.getValue());
        }
        return result;
    }

    private NamespaceDto assembleNamespace(String env, String app, String namespace) {
        NamespaceDto namespaceDto = new NamespaceDto();
        namespaceDto.setNamespaceName(namespace);
        if(Constant.RESERVED_WORD_GLOBAL.equals(namespace)){
            namespaceDto.setId(1L);
        }else if(Constant.RESERVED_WORD_ENV.equals(namespace)){
            namespaceDto.setEnvName(env);
            namespaceDto.setId(2L);
        }else{
            namespaceDto.setAppName(app);
            namespaceDto.setEnvName(env);
            namespaceDto.setId(3L);
        }
        return namespaceDto;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        try{
            zkClient = ZkClient.getInstance(registryUrl);
        }catch (Exception ex){
            log.error("connect to zk exception: [{}]", ExceptionUtil.getDetailMessage(ex));
        }
    }

}
